# 在当前文件夹下写一个flask框架的前后端 代码，实现的功能有:
# 1.前端页面是一个类似于腾讯视频，爱奇艺，这种视频点击对应的视频，可以播放视频
# 2.后端实现视频的播放，视频的播放需要使用m3u8格式
# 3.后端需要实现视频的播放进度条，可以拖动进度条，可以暂停，可以继续播放
# 4.后端需要实现视频的播放速度，可以调节播放速度
# 5.后端需要实现视频的播放亮度，可以调节播放亮度
# 6.后端需要实现视频的播放音量，可以调节播放音量
# 7.后端需要实现视频的播放进度条，可以拖动进度条，可以暂停，可以继续播放
# 8.后端需要实现视频的播放列表，可以点击播放列表中的视频，播放对应的视频
# 9.后端需要实现视频的下一集，可以点击下一集，播放下一集
# 10.后端需要实现视频的上一集，可以点击上一集，播放上一集
# 11.前端需要展示热播的剧集海报，名称，播放量，豆瓣评分，主演，导演，地区，类型，简介
# 12.前端需要等待客户点击了对应的剧集后跳转到该剧集的播放页面   
# 13.前端播放的视频是我给定的播放地址，播放地址是m3u8格式，https://137.175.38.151:11305/data2/jvods/hls/dhz/4/3272/25051220/3_39845_1921368/1920/index.m3u8?appId=kkdy&sign=266acaa5e50a8b9c6e4a657930c509ee&timestamp=1747107588&ref=2
# 14.前端播放页中给定一个大小，左侧3分之2是视频播放，右侧3分之1是剧集的介绍，剧集的介绍中需要展示剧集的海报，名称，豆瓣评分，主演，导演，地区，类型，简介，还有选集和切换下一集按钮

from flask import Flask, render_template, request, jsonify, redirect, url_for, session, flash
import os
import json
from werkzeug.security import generate_password_hash, check_password_hash
from functools import wraps

app = Flask(__name__)
app.secret_key = os.urandom(24)  # 用于session加密

# 用户数据文件
USERS_FILE = 'users.json'

# 用户认证装饰器
def login_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if 'user_id' not in session:
            flash('请先登录', 'error')
            return redirect(url_for('login'))
        return f(*args, **kwargs)
    return decorated_function

# 管理员验证装饰器
def admin_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if 'user_id' not in session:
            flash('请先登录', 'error')
            return redirect(url_for('login'))
        users_data = load_users()
        user = next((u for u in users_data['users'] if str(u['id']) == str(session.get('user_id'))), None)
        if not user or user.get('role') != 'admin':
            flash('需要管理员权限', 'error')
            return redirect(url_for('index'))
        return f(*args, **kwargs)
    return decorated_function

# 用户数据加载和保存
def load_users():
    try:
        if os.path.exists(USERS_FILE):
            with open(USERS_FILE, 'r', encoding='utf-8') as f:
                return json.load(f)
        return {'users': []}
    except Exception as e:
        print(f"加载用户数据失败: {str(e)}")
        return {'users': []}

def save_users(users_data):
    try:
        with open(USERS_FILE, 'w', encoding='utf-8') as f:
            json.dump(users_data, f, ensure_ascii=False, indent=4)
    except Exception as e:
        print(f"保存用户数据失败: {str(e)}")
        flash('保存数据失败', 'error')

# 视频数据加载和保存
def load_videos():
    try:
        with open('videos.json', 'r', encoding='utf-8') as f:
            return json.load(f)
    except Exception as e:
        print(f"加载视频数据失败: {str(e)}")
        return {'videos': []}

def save_videos(videos_data):
    try:
        with open('videos.json', 'w', encoding='utf-8') as f:
            json.dump(videos_data, f, ensure_ascii=False, indent=4)
    except Exception as e:
        print(f"保存视频数据失败: {str(e)}")
        flash('保存数据失败', 'error')

# 获取当前用户
def get_current_user():
    if 'user_id' not in session:
        return None
    users_data = load_users()
    return next((u for u in users_data['users'] if str(u['id']) == str(session.get('user_id'))), None)

# 登录处理
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form.get('username')
        password = request.form.get('password')
        remember = request.form.get('remember')
        
        if not username or not password:
            flash('请填写用户名和密码', 'error')
            return render_template('login.html')
        
        users_data = load_users()
        user = next((u for u in users_data['users'] if u['username'] == username), None)
        
        if user and check_password_hash(user['password'], password):
            session['user_id'] = str(user['id'])
            session['username'] = user['username']
            session['role'] = user.get('role', 'user')
            if remember:
                session.permanent = True
            flash('登录成功', 'success')
            return redirect(url_for('index'))
        
        flash('用户名或密码错误', 'error')
        return render_template('login.html')
    
    return render_template('login.html')

# 注册处理
@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form.get('username')
        email = request.form.get('email')
        password = request.form.get('password')
        confirm_password = request.form.get('confirm_password')
        
        if not all([username, email, password, confirm_password]):
            flash('请填写所有必填字段', 'error')
            return render_template('register.html')
        
        if password != confirm_password:
            flash('两次输入的密码不一致', 'error')
            return render_template('register.html')
        
        users_data = load_users()
        
        if any(u['username'] == username for u in users_data['users']):
            flash('用户名已存在', 'error')
            return render_template('register.html')
        
        if any(u['email'] == email for u in users_data['users']):
            flash('邮箱已被注册', 'error')
            return render_template('register.html')
        
        new_user = {
            'id': len(users_data['users']) + 1,
            'username': username,
            'email': email,
            'password': generate_password_hash(password),
            'role': 'user',
            'favorites': [],
            'history': []
        }
        
        users_data['users'].append(new_user)
        save_users(users_data)
        
        session['user_id'] = str(new_user['id'])
        session['username'] = new_user['username']
        session['role'] = 'user'
        
        flash('注册成功', 'success')
        return redirect(url_for('index'))
    
    return render_template('register.html')

# 退出登录
@app.route('/logout')
def logout():
    session.clear()
    return redirect(url_for('index'))

# 用户资料页面
@app.route('/profile')
@login_required
def profile():
    users_data = load_users()
    user = next((u for u in users_data['users'] if str(u['id']) == str(session.get('user_id'))), None)
    if not user:
        flash('用户不存在', 'error')
        return redirect(url_for('login'))
    
    return render_template('profile.html', user=user)

# 更新用户密码
@app.route('/update_password', methods=['POST'])
@login_required
def update_password():
    users_data = load_users()
    user = next((u for u in users_data['users'] if str(u['id']) == str(session.get('user_id'))), None)
    if not user:
        flash('用户不存在', 'error')
        return redirect(url_for('login'))
    
    new_password = request.form.get('new_password')
    confirm_password = request.form.get('confirm_password')
    
    if not new_password or not confirm_password:
        flash('请填写所有密码字段', 'error')
        return redirect(url_for('profile'))
    
    if new_password != confirm_password:
        flash('两次输入的密码不一致', 'error')
        return redirect(url_for('profile'))
    
    user['password'] = generate_password_hash(new_password)
    save_users(users_data)
    
    flash('密码修改成功', 'success')
    return redirect(url_for('profile'))

# 检查是否已收藏
@app.route('/check_favorite', methods=['POST'])
@login_required
def check_favorite():
    try:
        video_id = request.form.get('video_id')
        if not video_id:
            return jsonify({'success': False, 'message': '视频ID不能为空'})
        
        user = get_current_user()
        if not user:
            return jsonify({'success': False, 'message': '用户不存在'})
        
        favorites = user.get('favorites', [])
        is_favorite = str(video_id) in [str(fav) for fav in favorites]
        
        return jsonify({
            'success': True,
            'is_favorite': is_favorite
        })
    except Exception as e:
        print(f"检查收藏状态失败: {str(e)}")
        return jsonify({'success': False, 'message': '操作失败'})

# 添加收藏
@app.route('/add_favorite', methods=['POST'])
@login_required
def add_favorite():
    try:
        video_id = request.form.get('video_id')
        if not video_id:
            return jsonify({'success': False, 'message': '视频ID不能为空'})
        
        users_data = load_users()
        user = next((u for u in users_data['users'] if str(u['id']) == str(session.get('user_id'))), None)
        if not user:
            return jsonify({'success': False, 'message': '用户不存在'})
        
        if 'favorites' not in user:
            user['favorites'] = []
        
        video_id = str(video_id)
        favorites = [str(fav) for fav in user['favorites']]
        
        if video_id in favorites:
            user['favorites'] = [fav for fav in user['favorites'] if str(fav) != video_id]
            action = 'removed'
        else:
            user['favorites'].append(video_id)
            action = 'added'
        
        save_users(users_data)
        return jsonify({'success': True, 'action': action})
    except Exception as e:
        print(f"收藏操作失败: {str(e)}")
        return jsonify({'success': False, 'message': '操作失败'})

# 添加观看历史
@app.route('/add_history', methods=['POST'])
@login_required
def add_history():
    try:
        video_id = request.form.get('video_id')
        if not video_id:
            return jsonify({'success': False, 'message': '视频ID不能为空'})
        
        users_data = load_users()
        user = next((u for u in users_data['users'] if str(u['id']) == str(session.get('user_id'))), None)
        if not user:
            return jsonify({'success': False, 'message': '用户不存在'})
        
        if 'history' not in user:
            user['history'] = []
        
        video_id = str(video_id)
        history = [str(h) for h in user['history']]
        
        # 如果视频已经在历史记录中，则移除它
        if video_id in history:
            user['history'] = [h for h in user['history'] if str(h) != video_id]
        
        # 将视频添加到历史记录的开头
        user['history'].insert(0, video_id)
        
        # 限制历史记录数量为50个
        user['history'] = user['history'][:50]
        
        save_users(users_data)
        return jsonify({'success': True})
    except Exception as e:
        print(f"添加观看历史失败: {str(e)}")
        return jsonify({'success': False, 'message': '操作失败'})

# 获取用户历史记录
@app.route('/get_history')
@login_required
def get_history():
    try:
        user = get_current_user()
        if not user:
            return jsonify({'success': False, 'message': '用户不存在'})
        
        history = user.get('history', [])
        history_videos = []
        videos_data = load_videos()
        videos = videos_data['videos']
        
        for video_id in history:
            video = next((v for v in videos if str(v['id']) == str(video_id)), None)
            if video:
                history_videos.append(video)
        
        return jsonify({'success': True, 'videos': history_videos})
    except Exception as e:
        print(f"获取观看历史失败: {str(e)}")
        return jsonify({'success': False, 'message': '获取历史记录失败'})

# 获取用户收藏
@app.route('/get_favorites')
@login_required
def get_favorites():
    try:
        user = get_current_user()
        if not user:
            return jsonify({'success': False, 'message': '用户不存在'})
        
        favorites = user.get('favorites', [])
        favorite_videos = []
        videos_data = load_videos()
        videos = videos_data['videos']
        
        for video_id in favorites:
            video = next((v for v in videos if str(v['id']) == str(video_id)), None)
            if video:
                favorite_videos.append(video)
        
        return jsonify({'success': True, 'videos': favorite_videos})
    except Exception as e:
        print(f"获取收藏列表失败: {str(e)}")
        return jsonify({'success': False, 'message': '获取收藏列表失败'})

# 首页 - 视频列表
@app.route('/')
def index():
    videos_data = load_videos()
    query = request.args.get('q', '').strip()
    if query:
        filtered_videos = [v for v in videos_data['videos'] if query.lower() in v['title'].lower()]
    else:
        filtered_videos = videos_data['videos']
    return render_template('index.html', videos=filtered_videos, search_query=query, active_nav='home')

# 播放页
@app.route('/play/<video_id>')
def play(video_id):
    try:
        videos_data = load_videos()
        video = next((v for v in videos_data['videos'] if str(v['id']) == str(video_id)), None)
        if not video:
            flash('视频不存在', 'error')
            return redirect(url_for('index'))
        
        episode = request.args.get('episode', '1')
        available_episodes = []
        
        # 处理剧集编号
        if isinstance(video['url'], dict):
            for key in video['url'].keys():
                try:
                    num = ''.join(filter(str.isdigit, key))
                    if num:
                        num = int(num)
                        available_episodes.append({
                            'num': num,
                            'key': key
                        })
                except ValueError:
                    continue
        else:
            available_episodes.append({
                'num': 1,
                'key': '第1集'
            })
        
        # 按数字排序
        available_episodes.sort(key=lambda x: x['num'])
        
        # 获取当前剧集信息
        current_episode = next((ep for ep in available_episodes if str(ep['num']) == episode), None)
        if not current_episode:
            current_episode = available_episodes[0] if available_episodes else None
        
        # 获取上一集和下一集
        prev_episode = None
        next_episode = None
        if current_episode:
            current_index = available_episodes.index(current_episode)
            if current_index > 0:
                prev_episode = available_episodes[current_index - 1]['num']
            if current_index < len(available_episodes) - 1:
                next_episode = available_episodes[current_index + 1]['num']
        
        # 获取当前剧集的视频URL
        video_url = video['url'].get(current_episode['key'], '') if isinstance(video['url'], dict) else video['url']
        
        # 判断视频类型
        video_type = 'm3u8' if video_url.endswith('.m3u8') else 'mp4' if video_url.endswith('.mp4') else ''
        
        # 根据视频分类确定active_nav
        active_nav = 'home'
        if '电影' in video.get('category', ''):
            active_nav = 'movie'
        elif '电视剧' in video.get('category', ''):
            active_nav = 'tv'
        elif '动漫' in video.get('category', '') or '动画' in video.get('category', ''):
            active_nav = 'anime'
        elif '综艺' in video.get('category', ''):
            active_nav = 'variety'
        
        return render_template('play.html',
                             video=video,
                             video_url=video_url,
                             video_type=video_type,
                             episode=current_episode['num'] if current_episode else 1,
                             available_episodes=available_episodes,
                             prev_episode=prev_episode,
                             next_episode=next_episode,
                             videos=videos_data['videos'],
                             active_nav=active_nav,
                             search_query='')
    except Exception as e:
        print(f"加载播放页面失败: {str(e)}")
        flash('加载视频失败', 'error')
        return redirect(url_for('index'))

# API - 更新播放进度
@app.route('/api/progress/<int:video_id>', methods=['POST'])
def update_progress(video_id):
    data = request.json
    progress = data.get('progress')
    
    # 这里可以将进度保存到数据库
    print(f"Video {video_id} progress: {progress}")
    
    return jsonify({"status": "success"})

# 分类页 - 电影
@app.route('/category/movie')
def category_movie():
    videos_data = load_videos()
    filtered_videos = [v for v in videos_data['videos'] if '电影' in v.get('category', '')]
    return render_template('index.html', videos=filtered_videos, search_query='', active_nav='movie')

# 分类页 - 电视剧
@app.route('/category/tv')
def category_tv():
    videos_data = load_videos()
    filtered_videos = [v for v in videos_data['videos'] if '电视剧' in v.get('category', '')]
    return render_template('index.html', videos=filtered_videos, search_query='', active_nav='tv')

# 分类页 - 动漫（含"动漫"或"动画"）
@app.route('/category/anime')
def category_anime():
    videos_data = load_videos()
    filtered_videos = [v for v in videos_data['videos'] if ('动漫' in v.get('category', '')) or ('动画' in v.get('category', ''))]
    return render_template('index.html', videos=filtered_videos, search_query='', active_nav='anime')

# 分类页 - 综艺
@app.route('/category/variety')
def category_variety():
    videos_data = load_videos()
    filtered_videos = [v for v in videos_data['videos'] if '综艺' in v.get('category', '')]
    return render_template('index.html', videos=filtered_videos, search_query='', active_nav='variety')

# 管理员控制面板
@app.route('/admin')
@admin_required
def admin_dashboard():
    try:
        users_data = load_users()
        videos_data = load_videos()
        return render_template('admin/dashboard.html',
                             users=users_data['users'],
                             videos=videos_data['videos'])
    except Exception as e:
        print(f"加载管理控制台失败: {str(e)}")
        flash('加载管理控制台失败', 'error')
        return redirect(url_for('index'))

# 管理员 - 用户管理
@app.route('/admin/users')
@admin_required
def admin_users():
    try:
        users_data = load_users()
        return render_template('admin/users.html', users=users_data['users'])
    except Exception as e:
        print(f"加载用户管理页面失败: {str(e)}")
        flash('加载用户管理页面失败', 'error')
        return redirect(url_for('admin_dashboard'))

# 管理员 - 视频管理
@app.route('/admin/videos')
@admin_required
def admin_videos():
    try:
        videos_data = load_videos()
        return render_template('admin/videos.html', videos=videos_data['videos'])
    except Exception as e:
        print(f"加载视频管理页面失败: {str(e)}")
        flash('加载视频管理页面失败', 'error')
        return redirect(url_for('admin_dashboard'))

# 管理员 - 添加视频
@app.route('/admin/videos/add', methods=['GET', 'POST'])
@admin_required
def admin_add_video():
    try:
        if request.method == 'POST':
            videos_data = load_videos()
            new_video = {
                'id': len(videos_data['videos']) + 1,
                'title': request.form.get('title'),
                'description': request.form.get('description'),
                'cover': request.form.get('cover'),
                'url': request.form.get('url'),
                'category': request.form.get('category'),
                'tags': request.form.get('tags', '').split(','),
                'rating': float(request.form.get('rating', 0)),
                'views': int(request.form.get('views', 0)),
                'year': request.form.get('year'),
                'director': request.form.get('director'),
                'cast': request.form.get('cast'),
                'region': request.form.get('region')
            }
            videos_data['videos'].append(new_video)
            save_videos(videos_data)
            flash('视频添加成功', 'success')
            return redirect(url_for('admin_videos'))
        return render_template('admin/add_video.html')
    except Exception as e:
        print(f"添加视频失败: {str(e)}")
        flash('添加视频失败', 'error')
        return redirect(url_for('admin_videos'))

# 管理员 - 编辑视频
@app.route('/admin/videos/edit/<int:video_id>', methods=['GET', 'POST'])
@admin_required
def admin_edit_video(video_id):
    try:
        videos_data = load_videos()
        video = next((v for v in videos_data['videos'] if v['id'] == video_id), None)
        if not video:
            flash('视频不存在', 'error')
            return redirect(url_for('admin_videos'))
        
        if request.method == 'POST':
            video['title'] = request.form.get('title')
            video['description'] = request.form.get('description')
            video['cover'] = request.form.get('cover')
            video['url'] = request.form.get('url')
            video['category'] = request.form.get('category')
            video['tags'] = request.form.get('tags', '').split(',')
            video['rating'] = float(request.form.get('rating', 0))
            video['views'] = int(request.form.get('views', 0))
            video['year'] = request.form.get('year')
            video['director'] = request.form.get('director')
            video['cast'] = request.form.get('cast')
            video['region'] = request.form.get('region')
            
            save_videos(videos_data)
            flash('视频更新成功', 'success')
            return redirect(url_for('admin_videos'))
        
        return render_template('admin/edit_video.html', video=video)
    except Exception as e:
        print(f"编辑视频失败: {str(e)}")
        flash('编辑视频失败', 'error')
        return redirect(url_for('admin_videos'))

# 管理员 - 删除视频
@app.route('/admin/videos/delete/<int:video_id>', methods=['POST'])
@admin_required
def admin_delete_video(video_id):
    try:
        videos_data = load_videos()
        videos_data['videos'] = [v for v in videos_data['videos'] if v['id'] != video_id]
        save_videos(videos_data)
        flash('视频删除成功', 'success')
        return redirect(url_for('admin_videos'))
    except Exception as e:
        print(f"删除视频失败: {str(e)}")
        flash('删除视频失败', 'error')
        return redirect(url_for('admin_videos'))

# 管理员 - 获取用户密码
@app.route('/admin/users/get-password/<int:user_id>')
@admin_required
def admin_get_password(user_id):
    try:
        users_data = load_users()
        user = next((u for u in users_data['users'] if u['id'] == user_id), None)
        if not user:
            return jsonify({'success': False, 'error': '用户不存在'}), 404
        
        return jsonify({
            'success': True,
            'password': user['password']
        })
    except Exception as e:
        print(f"获取用户密码失败: {str(e)}")
        return jsonify({'success': False, 'error': '获取密码失败'}), 500

# 管理员 - 重置用户密码
@app.route('/admin/users/reset-password/<int:user_id>', methods=['POST'])
@admin_required
def admin_reset_password(user_id):
    try:
        data = request.get_json()
        new_password = data.get('password')
        if not new_password:
            return jsonify({'error': '新密码不能为空'}), 400
        
        users_data = load_users()
        user = next((u for u in users_data['users'] if u['id'] == user_id), None)
        if not user:
            return jsonify({'error': '用户不存在'}), 404
        
        user['password'] = generate_password_hash(new_password)
        save_users(users_data)
        
        return jsonify({'message': '密码重置成功'})
    except Exception as e:
        print(f"重置用户密码失败: {str(e)}")
        return jsonify({'error': '重置密码失败'}), 500

# 管理员 - 删除用户
@app.route('/admin/users/delete/<int:user_id>', methods=['POST'])
@admin_required
def admin_delete_user(user_id):
    try:
        users_data = load_users()
        user = next((u for u in users_data['users'] if u['id'] == user_id), None)
        if not user:
            return jsonify({'error': '用户不存在'}), 404
        
        if user.get('role') == 'admin':
            return jsonify({'error': '不能删除管理员用户'}), 403
        
        users_data['users'] = [u for u in users_data['users'] if u['id'] != user_id]
        save_users(users_data)
        
        return jsonify({'message': '用户删除成功'})
    except Exception as e:
        print(f"删除用户失败: {str(e)}")
        return jsonify({'error': '删除用户失败'}), 500

if __name__ == '__main__':
    app.run(debug=True)    